#pragma once

#include <GL/glew.h>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <glm/glm.hpp>


namespace vortex
{
    enum ShaderType
    {
        Vertex = 0x01,
        Fragment,
        Geometry,
        Compute,
    };

    GLenum getShaderTypeEnum(ShaderType type);

    class Shader
    {
    private:
        ShaderType type;
        GLuint shader_id;
    public:
        Shader(const std::string& filepath, ShaderType type);
        ~Shader();

        GLuint GetId() const { return shader_id; }

    private:
        bool load_file(const std::string& filepath, std::vector<char>& source);
    };

    // A complete shader program
    class ShaderProgram
    {
    private:
        GLuint program_id;
        std::vector<std::shared_ptr<Shader>> shaders;

    public:
        ShaderProgram(const std::map<ShaderType, std::string>& sources);
        ~ShaderProgram();
        GLuint GetId() const { return program_id; }

        void Bind() const { glUseProgram(program_id); }
        void Unbind() const { glUseProgram(0); }

        void SetTextureUniform(const std::string& name, GLint textureSlot);
        void SetTextureArrayUniform(const std::string& name, GLint* values, int size);
        void SetUniformMat4(const std::string& name, const glm::mat4& values);
    };
}
